package com.oddfar.ztwz.business.handler;

import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

// 使用 Spring 的 TextWebSocketHandler 来处理 WebSocket 消息
@Component
@Slf4j
public class WebSocketServerHadller extends TextWebSocketHandler {

    // 初始化方法，在 Bean 初始化完成后执行，用于提示 WebSocket 服务已加载
    @PostConstruct
    public void init() {
        log.info("websocket 加载");
    }
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    // 存储每个用户对应的 WebSocketSession，键为用户 ID，值为 WebSocketSession 对象
    private final Map<String, WebSocketSession> connectedDevices = new ConcurrentHashMap<>();

    /**
     * 当客户端与服务器建立 WebSocket 连接成功时调用此方法
     *
     * @param session 客户端的 WebSocketSession 对象
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String userId = getUserId(session.getUri().getQuery());
        if (userId != null) {
            // 将用户 ID 和对应的 WebSocketSession 存入 connectedDevices 中
            connectedDevices.put(userId, session);
            log.info("用户 {} 已连接", userId);
            sendOfflineMessagesFromRedis(userId);
        } else {
            log.warn("无法从查询字符串中获取用户 ID，连接建立失败");
            session.close();
        }
    }

    // 从 Redis 中发送离线消息
    private void sendOfflineMessagesFromRedis(String userId) {
        WebSocketSession webSocketSession = connectedDevices.get(userId);
        String key = "offline_messages:" + userId;
        while (true) {
            String message = redisTemplate.opsForList().leftPop(key);
            if (message == null) {
                break;
            }
            if (webSocketSession != null && webSocketSession.isOpen()) {
                sendMessage(webSocketSession, message);
            }
        }
    }
    /**
     * 当客户端与服务器的 WebSocket 连接关闭时调用此方法
     *
     * @param session 客户端的 WebSocketSession 对象
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String userId = getUserId(session.getUri().getQuery());
        if (userId != null) {
            // 从 connectedDevices 中移除该用户的 WebSocketSession
            connectedDevices.remove(userId);
            log.info("用户 {} 已断开连接", userId);
        }
    }

    /**
     * 当服务器收到客户端发送的消息时调用此方法
     *
     * @param session 客户端的 WebSocketSession 对象
     * @param message 客户端发送的消息内容
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("来自客户端的消息：{}", message.getPayload());
        JSONObject jsonObject;
        try {
            jsonObject = JSONObject.parseObject(message.getPayload());
        } catch (Exception e) {
            log.error("消息解析失败: {}", message.getPayload(), e);
            return;
        }
        String targetUserId = jsonObject.getString("targetUserId");
        String senderUserId = getUserId(session.getUri().getQuery());
        if (targetUserId != null && senderUserId != null) {
            // 从 connectedDevices 中获取目标用户的 WebSocketSession
            log.info("在线信息：{}", connectedDevices.entrySet());
            WebSocketSession targetSession = connectedDevices.get(targetUserId);
            if (targetSession != null && targetSession.isOpen()) {
                // 向目标用户发送消息
                sendMessage(targetSession, message.getPayload());
            } else {
                String key = "offline_messages:" + targetUserId;
                redisTemplate.opsForList().rightPush(key, message.getPayload());
                log.warn("目标用户 {} 未连接，消息已存入 Redis 队列", targetUserId);            }
        }
    }

    /**
     * 当 WebSocket 连接出现错误时调用此方法
     *
     * @param session 客户端的 WebSocketSession 对象
     * @param exception 异常信息
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("发生错误：{}，Session ID：{}", exception.getMessage(), session.getId());
    }

    /**
     * 向指定客户端会话发送消息
     *
     * @param session 客户端的 WebSocketSession 对象
     * @param message 要发送的消息内容
     */
    public static void sendMessage(WebSocketSession session, String message) {
        try {
            // 通过 WebSocketSession 发送文本消息
            session.sendMessage(new TextMessage(message));
        } catch (IOException e) {
            log.error("发送消息出错：{}", e.getMessage());
        }
    }

    /**
     * 从查询字符串中提取用户 ID
     *
     * @param query 查询字符串
     * @return 用户 ID
     */
    private String getUserId(String query) {
        if (query == null) {
            return null;
        }
        try {
            // 对查询字符串进行 URL 解码
            query = URLDecoder.decode(query, String.valueOf(StandardCharsets.UTF_8));
            String[] params = query.split("&");
            for (String param : params) {
                String[] keyValue = param.split("=");
                if (keyValue.length == 2 && keyValue[0].equals("userId")) {
                    return keyValue[1];
                }
            }
        } catch (Exception e) {
            log.error("解析查询字符串时出错: {}", query, e);
        }
        return null;
    }
}